{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "549d4445",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Defaulting to user installation because normal site-packages is not writeable\n",
      "Requirement already satisfied: torch in /usr/local/lib/python3.10/dist-packages (2.4.0)\n",
      "Requirement already satisfied: transformers in /home/rshoemake/.local/lib/python3.10/site-packages (4.40.2)\n",
      "Requirement already satisfied: datasets in /home/rshoemake/.local/lib/python3.10/site-packages (2.20.0)\n",
      "Requirement already satisfied: filelock in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (3.14.0)\n",
      "Requirement already satisfied: typing-extensions>=4.8.0 in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (4.11.0)\n",
      "Requirement already satisfied: sympy in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (1.12)\n",
      "Requirement already satisfied: networkx in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (3.3)\n",
      "Requirement already satisfied: jinja2 in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (3.1.4)\n",
      "Requirement already satisfied: fsspec in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (2024.3.1)\n",
      "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.1.105 in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.1.105 in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.1.105 in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cudnn-cu12==9.1.0.70 in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (9.1.0.70)\n",
      "Requirement already satisfied: nvidia-cublas-cu12==12.1.3.1 in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (12.1.3.1)\n",
      "Requirement already satisfied: nvidia-cufft-cu12==11.0.2.54 in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (11.0.2.54)\n",
      "Requirement already satisfied: nvidia-curand-cu12==10.3.2.106 in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (10.3.2.106)\n",
      "Requirement already satisfied: nvidia-cusolver-cu12==11.4.5.107 in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (11.4.5.107)\n",
      "Requirement already satisfied: nvidia-cusparse-cu12==12.1.0.106 in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (12.1.0.106)\n",
      "Requirement already satisfied: nvidia-nccl-cu12==2.20.5 in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (2.20.5)\n",
      "Requirement already satisfied: nvidia-nvtx-cu12==12.1.105 in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (12.1.105)\n",
      "Requirement already satisfied: triton==3.0.0 in /home/rshoemake/.local/lib/python3.10/site-packages (from torch) (3.0.0)\n",
      "Requirement already satisfied: nvidia-nvjitlink-cu12 in /home/rshoemake/.local/lib/python3.10/site-packages (from nvidia-cusolver-cu12==11.4.5.107->torch) (12.4.127)\n",
      "Requirement already satisfied: huggingface-hub<1.0,>=0.19.3 in /home/rshoemake/.local/lib/python3.10/site-packages (from transformers) (0.21.2)\n",
      "Requirement already satisfied: numpy>=1.17 in /home/rshoemake/.local/lib/python3.10/site-packages (from transformers) (1.24.4)\n",
      "Requirement already satisfied: packaging>=20.0 in /home/rshoemake/.local/lib/python3.10/site-packages (from transformers) (23.2)\n",
      "Requirement already satisfied: pyyaml>=5.1 in /home/rshoemake/.local/lib/python3.10/site-packages (from transformers) (6.0.1)\n",
      "Requirement already satisfied: regex!=2019.12.17 in /home/rshoemake/.local/lib/python3.10/site-packages (from transformers) (2024.5.15)\n",
      "Requirement already satisfied: requests in /home/rshoemake/.local/lib/python3.10/site-packages (from transformers) (2.32.3)\n",
      "Requirement already satisfied: tokenizers<0.20,>=0.19 in /home/rshoemake/.local/lib/python3.10/site-packages (from transformers) (0.19.1)\n",
      "Requirement already satisfied: safetensors>=0.4.1 in /home/rshoemake/.local/lib/python3.10/site-packages (from transformers) (0.4.3)\n",
      "Requirement already satisfied: tqdm>=4.27 in /home/rshoemake/.local/lib/python3.10/site-packages (from transformers) (4.66.4)\n",
      "Requirement already satisfied: pyarrow>=15.0.0 in /home/rshoemake/.local/lib/python3.10/site-packages (from datasets) (16.1.0)\n",
      "Requirement already satisfied: pyarrow-hotfix in /home/rshoemake/.local/lib/python3.10/site-packages (from datasets) (0.6)\n",
      "Requirement already satisfied: dill<0.3.9,>=0.3.0 in /home/rshoemake/.local/lib/python3.10/site-packages (from datasets) (0.3.8)\n",
      "Requirement already satisfied: pandas in /home/rshoemake/.local/lib/python3.10/site-packages (from datasets) (2.2.2)\n",
      "Requirement already satisfied: xxhash in /home/rshoemake/.local/lib/python3.10/site-packages (from datasets) (3.4.1)\n",
      "Requirement already satisfied: multiprocess in /home/rshoemake/.local/lib/python3.10/site-packages (from datasets) (0.70.16)\n",
      "Requirement already satisfied: aiohttp in /home/rshoemake/.local/lib/python3.10/site-packages (from datasets) (3.9.5)\n",
      "Requirement already satisfied: aiosignal>=1.1.2 in /home/rshoemake/.local/lib/python3.10/site-packages (from aiohttp->datasets) (1.3.1)\n",
      "Requirement already satisfied: attrs>=17.3.0 in /home/rshoemake/.local/lib/python3.10/site-packages (from aiohttp->datasets) (23.2.0)\n",
      "Requirement already satisfied: frozenlist>=1.1.1 in /home/rshoemake/.local/lib/python3.10/site-packages (from aiohttp->datasets) (1.4.1)\n",
      "Requirement already satisfied: multidict<7.0,>=4.5 in /home/rshoemake/.local/lib/python3.10/site-packages (from aiohttp->datasets) (6.0.5)\n",
      "Requirement already satisfied: yarl<2.0,>=1.0 in /home/rshoemake/.local/lib/python3.10/site-packages (from aiohttp->datasets) (1.9.4)\n",
      "Requirement already satisfied: async-timeout<5.0,>=4.0 in /home/rshoemake/.local/lib/python3.10/site-packages (from aiohttp->datasets) (4.0.3)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /home/rshoemake/.local/lib/python3.10/site-packages (from requests->transformers) (3.3.2)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /home/rshoemake/.local/lib/python3.10/site-packages (from requests->transformers) (3.7)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /home/rshoemake/.local/lib/python3.10/site-packages (from requests->transformers) (1.26.6)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /home/rshoemake/.local/lib/python3.10/site-packages (from requests->transformers) (2024.2.2)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in /home/rshoemake/.local/lib/python3.10/site-packages (from jinja2->torch) (2.1.5)\n",
      "Requirement already satisfied: python-dateutil>=2.8.2 in /home/rshoemake/.local/lib/python3.10/site-packages (from pandas->datasets) (2.9.0.post0)\n",
      "Requirement already satisfied: pytz>=2020.1 in /home/rshoemake/.local/lib/python3.10/site-packages (from pandas->datasets) (2024.1)\n",
      "Requirement already satisfied: tzdata>=2022.7 in /home/rshoemake/.local/lib/python3.10/site-packages (from pandas->datasets) (2024.1)\n",
      "Requirement already satisfied: mpmath>=0.19 in /home/rshoemake/.local/lib/python3.10/site-packages (from sympy->torch) (1.3.0)\n",
      "Requirement already satisfied: six>=1.5 in /usr/lib/python3/dist-packages (from python-dateutil>=2.8.2->pandas->datasets) (1.16.0)\n",
      "\u001b[33mWARNING: Error parsing dependencies of send2trash: Expected matching RIGHT_PARENTHESIS for LEFT_PARENTHESIS, after version specifier\n",
      "    sys-platform (==\"darwin\") ; extra == 'objc'\n",
      "                 ~^\u001b[0m\u001b[33m\n",
      "\u001b[0m"
     ]
    }
   ],
   "source": [
    "!pip install torch transformers datasets  --quiet"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "fe0f9561",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Some weights of BertForSequenceClassification were not initialized from the model checkpoint at bert-base-uncased and are newly initialized: ['classifier.bias', 'classifier.weight']\n",
      "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model device: cuda:0\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "    <div>\n",
       "      \n",
       "      <progress value='3126' max='1563' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
       "      [1563/1563 16:03]\n",
       "    </div>\n",
       "    "
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Initial Model Performance: {'eval_loss': 0.7143436074256897, 'eval_accuracy': 0.50076, 'eval_runtime': 195.7528, 'eval_samples_per_second': 127.712, 'eval_steps_per_second': 7.985}\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "    <div>\n",
       "      \n",
       "      <progress value='4689' max='4689' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
       "      [4689/4689 38:48, Epoch 3/3]\n",
       "    </div>\n",
       "    <table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       " <tr style=\"text-align: left;\">\n",
       "      <th>Epoch</th>\n",
       "      <th>Training Loss</th>\n",
       "      <th>Validation Loss</th>\n",
       "      <th>Accuracy</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>0.298300</td>\n",
       "      <td>0.223037</td>\n",
       "      <td>0.914080</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>0.128000</td>\n",
       "      <td>0.231688</td>\n",
       "      <td>0.934800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>0.059100</td>\n",
       "      <td>0.289004</td>\n",
       "      <td>0.939520</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table><p>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "\n",
       "    <div>\n",
       "      \n",
       "      <progress value='3126' max='1563' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
       "      [1563/1563 44:25]\n",
       "    </div>\n",
       "    "
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Post-training Model Performance: {'eval_loss': 0.28900426626205444, 'eval_accuracy': 0.93952, 'eval_runtime': 197.4132, 'eval_samples_per_second': 126.638, 'eval_steps_per_second': 7.917, 'epoch': 3.0}\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "0b53d4c7c93c4a8b9caf52a337aedb7d",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/1563 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "We strongly recommend passing in an `attention_mask` since your input_ids may be padded. See https://huggingface.co/docs/transformers/troubleshooting#incorrect-output-when-padding-tokens-arent-masked.\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "7a9705a87c1e4b77a084311f3ff947f4",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/3 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "d5255fa8720247b3bb780ba2f2137076",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/1563 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "a09da0afe7d94f7cb1512e6b59b67420",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/1563 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "94beffdbfcf043cf87db328d3bb7631c",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/1563 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'eval_loss': 0.28900426626205444, 'eval_accuracy': 0.93952, 'eval_runtime': 197.4955, 'eval_samples_per_second': 126.585, 'eval_steps_per_second': 7.914, 'epoch': 3.0}\n"
     ]
    }
   ],
   "source": [
    "from transformers import BertTokenizer, BertForSequenceClassification, Trainer, TrainingArguments\n",
    "from datasets import load_dataset\n",
    "from tqdm.notebook import tqdm\n",
    "import numpy as np\n",
    "from seqeval.metrics import classification_report, accuracy_score\n",
    "import torch  \n",
    "\n",
    "# Load dataset and tokenizer\n",
    "dataset = load_dataset('imdb')\n",
    "tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')\n",
    "\n",
    "# Define compute metrics function\n",
    "def compute_metrics(p):\n",
    "    predictions, labels = p\n",
    "    predictions = np.argmax(predictions, axis=1)\n",
    "    accuracy = accuracy_score(labels, predictions)\n",
    "    return {\"accuracy\": accuracy}\n",
    "\n",
    "# Tokenize dataset\n",
    "def tokenize_function(examples):\n",
    "    return tokenizer(examples['text'], padding=\"max_length\", truncation=True)\n",
    "\n",
    "tokenized_datasets = dataset.map(tokenize_function, batched=True)\n",
    "tokenized_datasets = tokenized_datasets.remove_columns([\"text\"])\n",
    "tokenized_datasets.set_format(\"torch\")\n",
    "\n",
    "# Initialize model\n",
    "model = BertForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=2)\n",
    "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "model = model.to(device)\n",
    "\n",
    "# Set training arguments\n",
    "training_args = TrainingArguments(\n",
    "    output_dir='./results',\n",
    "    num_train_epochs=3,\n",
    "    per_device_train_batch_size=16,\n",
    "    per_device_eval_batch_size=16,\n",
    "    evaluation_strategy=\"epoch\",\n",
    "    save_strategy=\"epoch\",\n",
    "    logging_dir='./logs',\n",
    "    logging_steps=1000,\n",
    "    save_steps=1000,\n",
    ")\n",
    "\n",
    "# Initialize Trainer\n",
    "trainer = Trainer(\n",
    "    model=model,\n",
    "    args=training_args,\n",
    "    train_dataset=tokenized_datasets['train'],\n",
    "    eval_dataset=tokenized_datasets['test'],\n",
    "    tokenizer=tokenizer,\n",
    "    compute_metrics=compute_metrics\n",
    ")\n",
    "\n",
    "print(f\"Model device: {next(model.parameters()).device}\")\n",
    "\n",
    "# Evaluate the model\n",
    "results = trainer.evaluate()\n",
    "print(f\"Initial Model Performance: {results}\")\n",
    "\n",
    "# Train the model\n",
    "trainer.train()\n",
    "\n",
    "# Evaluate the model\n",
    "results = trainer.evaluate()\n",
    "print(f\"Post-training Model Performance: {results}\")\n",
    "\n",
    "\n",
    "import numpy as np\n",
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "# Function to monitor drift\n",
    "def monitor_drift(new_data, model, tokenizer):\n",
    "    device = next(model.parameters()).device\n",
    "    tokenized_new_data = tokenizer(new_data['text'], padding=\"max_length\", truncation=True, return_tensors=\"pt\")\n",
    "    tokenized_new_data = {k: v.to(device) for k, v in tokenized_new_data.items()}\n",
    "    predictions = model(**tokenized_new_data).logits\n",
    "    predicted_labels = np.argmax(predictions.cpu().detach().numpy(), axis=1)\n",
    "    accuracy = accuracy_score(new_data['label'], predicted_labels)\n",
    "    return accuracy < 0.75\n",
    "\n",
    "# Example of usage\n",
    "new_data = {\"text\": [\"New review text\"], \"label\": [1]}  # Replace with real data\n",
    "if monitor_drift(new_data, model, tokenizer):\n",
    "    # Retrain the model with new trainer using updated data\n",
    "    trainer.train()\n",
    "    \n",
    "    \n",
    "import torch  \n",
    "from torch import nn, autograd\n",
    "\n",
    "class EWC(object):\n",
    "    def __init__(self, model, dataloader, importance=1000):\n",
    "        self.model = model\n",
    "        self.device = next(model.parameters()).device\n",
    "        self.importance = importance\n",
    "        self.params = {n: p.clone() for n, p in self.model.named_parameters() if p.requires_grad}\n",
    "        self.fisher = self.compute_fisher_information(dataloader)\n",
    "\n",
    "    def compute_fisher_information(self, dataloader):\n",
    "        fisher = {n: torch.zeros_like(p) for n, p in self.model.named_parameters() if p.requires_grad}\n",
    "        self.model.eval()\n",
    "        for batch in tqdm(dataloader):\n",
    "            self.model.zero_grad()\n",
    "            input_ids = batch['input_ids'].to(self.model.device)\n",
    "            labels = batch['labels'].to(self.model.device)\n",
    "            output = self.model(input_ids).logits\n",
    "            loss = nn.CrossEntropyLoss()(output, labels)\n",
    "            loss.backward()\n",
    "            for n, p in self.model.named_parameters():\n",
    "                if p.requires_grad:\n",
    "                    fisher[n] += (p.grad ** 2) / len(dataloader)\n",
    "        return fisher\n",
    "\n",
    "    def penalty(self):\n",
    "        loss = 0\n",
    "        for n, p in self.model.named_parameters():\n",
    "            if p.requires_grad:\n",
    "                loss += torch.sum(self.fisher[n] * (p - self.params[n]) ** 2)\n",
    "        return self.importance * loss\n",
    "\n",
    "# Example of applying EWC during training\n",
    "ewc = EWC(model, trainer.get_train_dataloader())\n",
    "\n",
    "# Modify the training loop\n",
    "for epoch in tqdm(range(3)):\n",
    "    for batch in tqdm(trainer.get_train_dataloader()):\n",
    "        inputs = batch['input_ids'].to(model.device)\n",
    "        labels = batch['labels'].to(model.device)\n",
    "        outputs = model(inputs)\n",
    "        loss = nn.CrossEntropyLoss()(outputs.logits, labels)\n",
    "        ewc_loss = ewc.penalty()\n",
    "        total_loss = loss + ewc_loss\n",
    "        total_loss.backward()\n",
    "        trainer.optimizer.step()\n",
    "        trainer.optimizer.zero_grad()\n",
    "\n",
    "\n",
    "# Function to refine learning process\n",
    "def refine_learning(trainer, eval_dataset, target_accuracy=0.85):\n",
    "    results = trainer.evaluate(eval_dataset=eval_dataset)\n",
    "    print(results)\n",
    "    current_accuracy = results['eval_accuracy']\n",
    "\n",
    "    if current_accuracy < target_accuracy:\n",
    "        print(f\"Refining learning process... Current accuracy: {current_accuracy}\")\n",
    "        trainer.args.num_train_epochs += 1  # Example adjustment\n",
    "        trainer.train()\n",
    "\n",
    "# Example of usage\n",
    "refine_learning(trainer, tokenized_datasets['test'])\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
